import logging
from datetime import datetime
from typing import Any, Dict, List, Optional, Type

from pydantic import BaseModel, TypeAdapter
from PySide6.QtCore import QAbstractTableModel, QModelIndex, QSortFilterProxyModel, Qt
from PySide6.QtWidgets import QMessageBox

logger = logging.getLogger(__name__)


class SimpleMemoryModel(QAbstractTableModel):
    """基于内存的简单表格模型，使用Pydantic模型存储数据"""

    def __init__(
        self,
        model_class: Type[BaseModel],
        parent=None,
        non_data_fields_dict: Optional[Dict[str, str]] = None,
    ):
        super().__init__(parent)
        self.parent_widget = parent
        self.model_class = model_class
        self.current_data: List[BaseModel] = []
        self.current_user_data: List[Any] = []
        # 初始化字段信息
        self.data_fields = []
        self.data_field_names = []
        self.non_data_fields = []
        self.non_data_field_names = []

        last_field_entries = []  # 保存 (name, field_title) 对

        for name, field in self.model_class.model_fields.items():
            display_name = field.title or name  # 使用 title 作为显示名，没有则用字段名
            field_json_schema_extra = field.json_schema_extra or {}
            if field_json_schema_extra.get("last_field", False):
                last_field_entries.append((name, display_name))
            else:
                # 普通字段，先加入列表
                self.data_fields.append(name)
                self.data_field_names.append(display_name)

        # 最后将特殊字段追加到列表末尾
        for name, display_name in last_field_entries:
            self.data_fields.append(name)
            self.data_field_names.append(display_name)

        # 如果需要操作列，添加到字段列表
        if non_data_fields_dict:
            self.non_data_fields.extend(non_data_fields_dict.keys())
            self.non_data_field_names.extend(non_data_fields_dict.values())

        self.fields = self.data_fields + self.non_data_fields
        self.field_names = self.data_field_names + self.non_data_field_names

    def rowCount(self, parent=None):
        return len(self.current_data)

    def columnCount(self, parent=None):
        return len(self.fields)

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if not index.isValid():
            return None

        row = index.row()
        col = index.column()

        if row >= len(self.current_data):
            return None

        item = self.current_data[row]
        field_name = self.fields[col]
        value = getattr(item, field_name, None)

        if role == Qt.ItemDataRole.DisplayRole or role == Qt.ItemDataRole.EditRole:
            if isinstance(value, datetime):
                return value.strftime("%Y-%m-%d %H:%M:%S")
            return str(value) if value is not None else ""
        return None

    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if (
            orientation == Qt.Orientation.Horizontal
            and role == Qt.ItemDataRole.DisplayRole
        ):
            if section < len(self.field_names):
                return self.field_names[section]
        elif (
            orientation == Qt.Orientation.Horizontal
            and role == Qt.ItemDataRole.UserRole
        ):
            return self.fields[section]
        return None

    def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
        if index.isValid() and role == Qt.ItemDataRole.EditRole:
            row = index.row()
            col = index.column()

            if row >= len(self.current_data):
                return False

            item = self.current_data[row]
            field_name = self.fields[col]

            try:
                # 类型转换
                field_type = self.model_class.model_fields[field_name].annotation
                if field_type is not None:
                    type_adapter = TypeAdapter(field_type)
                    converted_value = type_adapter.validate_python(value)
                    setattr(item, field_name, converted_value)

                self.dataChanged.emit(index, index)
                return True
            except Exception as e:
                QMessageBox.warning(
                    self.parent_widget, "数据错误", f"无法更新数据: {str(e)}"
                )
                return False
        return False

    def flags(self, index):
        if not index.isValid():
            return Qt.ItemFlag.NoItemFlags

        # 允许单元格被编辑
        field = self.fields[index.column()]
        if field in self.non_data_fields:
            return (
                super().flags(index)
                | Qt.ItemFlag.ItemIsEnabled
                | Qt.ItemFlag.ItemIsSelectable
            )
        json_schema_extra = self.model_class.model_fields[field].json_schema_extra
        if json_schema_extra and json_schema_extra.get("uneditable"):
            return (
                super().flags(index)
                | Qt.ItemFlag.ItemIsEnabled
                | Qt.ItemFlag.ItemIsSelectable
            )
        return (
            super().flags(index)
            | Qt.ItemFlag.ItemIsEditable
            | Qt.ItemFlag.ItemIsEnabled
            | Qt.ItemFlag.ItemIsSelectable
        )

    def add_item(self, item: BaseModel, user_data: Any = None) -> bool:
        """添加新项到内存"""
        try:
            self.beginInsertRows(
                QModelIndex(), len(self.current_data), len(self.current_data)
            )
            self.current_data.append(item)
            self.current_user_data.append(user_data)
            self.endInsertRows()
            return True
        except Exception as e:
            QMessageBox.critical(
                self.parent_widget, "添加失败", f"无法添加记录: {str(e)}"
            )
            return False

    def remove_item(self, index: QModelIndex) -> bool:
        """从内存移除项"""
        if not index.isValid():
            return False

        row = index.row()
        if row >= len(self.current_data):
            return False

        self.beginRemoveRows(QModelIndex(), row, row)
        del self.current_data[row]
        del self.current_user_data[row]
        self.endRemoveRows()
        return True

    def remove_all_items(self) -> None:
        """移除所有项"""
        self.beginRemoveRows(QModelIndex(), 0, len(self.current_data) - 1)
        self.current_data.clear()
        self.current_user_data.clear()
        self.endRemoveRows()

    def get_item(
        self, index: QModelIndex, role: Qt.ItemDataRole = Qt.ItemDataRole.DisplayRole
    ) -> Optional[BaseModel]:
        """获取指定索引的项目"""
        if index.isValid() and index.row() < len(self.current_data):
            if role == Qt.ItemDataRole.DisplayRole:
                return self.current_data[index.row()]
            elif role == Qt.ItemDataRole.UserRole:
                return self.current_user_data[index.row()]
        return None

    def get_column_index(self, field_name: str) -> int:
        """获取字段名对应的列索引"""
        try:
            return self.fields.index(field_name)
        except ValueError:
            return -1


class SimpleSortFilterProxyModel(QSortFilterProxyModel):
    """简单的筛选排序代理模型"""

    def __init__(self, parent=None):
        super().__init__(parent)
        self._filter_text = ""
        self._filter_fields = []

    def set_filter(
        self, filter_text: str, filter_fields: Optional[List[str]] = None
    ) -> None:
        """设置筛选条件"""
        self._filter_text = filter_text
        self._filter_fields = filter_fields if filter_fields is not None else []
        self.invalidateFilter()

    def filterAcceptsRow(self, source_row, source_parent):
        if not self._filter_text:
            return True

        source_model = self.sourceModel()
        if not isinstance(source_model, SimpleMemoryModel):
            return True

        item = source_model.current_data[source_row]
        fields_to_check = (
            self._filter_fields if self._filter_fields else source_model.data_fields
        )

        for field in fields_to_check:
            value = str(getattr(item, field, "")).lower()
            if self._filter_text.lower() in value:
                return True

        return False
